package edu.ntu.cloudroid.model.data;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.jdo.annotations.Discriminator;
import javax.jdo.annotations.DiscriminatorStrategy;
import javax.jdo.annotations.FetchGroup;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.Inheritance;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.datastore.Key;
import com.sun.xacml.ctx.RequestCtx;

import edu.ntu.cloudroid.model.GAEData;
import edu.ntu.cloudroid.model.IDs;
import edu.ntu.cloudroid.model.UserData;
import edu.ntu.cloudroid.model.profile.ProfileData;

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
@Inheritance
@Discriminator(strategy=DiscriminatorStrategy.CLASS_NAME)
@FetchGroup(name = AbstractData.FETCH_GROUP_NAME, members = { @Persistent(name = "person") })
public abstract class AbstractData implements Serializable, GAEData{	
	
	public static final String FETCH_GROUP_NAME = "withPerson";
	private static final long serialVersionUID = 1L;
	@PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;
	
	@Persistent
	private String name;
	
	@Persistent
	private Date timestamp;

	
	//@Persistent
	//private Profile profile;
	

	public abstract AbstractData getInstance();


	public abstract int getDataId();
	
	public AbstractData(){
		
	}
	
	//some policies require inputs from users, each type of data
	//has a different way to reconstruct the object from the request
	//refer to LocationRequestWithInput for example
	public abstract AbstractData getDataFromRequest(RequestCtx requestCtx) throws Exception;
	
	//params may contain the specific column index
	//-1 means returns everything
	public abstract DetachedData detach(Object params); 
	
	//-1: le, 0: equal, 1: ge	
	public abstract int compareTo(String v, int idx);
	
	public abstract int compareTo(AbstractData v, int idx);		
	
	public abstract Object getWindowAverage(List<AbstractData> list, int idx) throws Exception;
		
	//change the object's granuality, return a DetachedData
	//for Location data, precise loc -> city -> country
	//for VitalSign data, precise val -> range (max,min)
	public abstract Object changeGranuality(int granuality, int colIdx) throws Exception;
	
	public abstract AbstractData initialize(String[] entries) throws Exception;
	
	@Override
	public UserData getMetaData(Object param){
		return null;
	}
	
	public Key getKey() {
		return key;
	}
	
	public String getName(){
		return this.name;
	}
	
	public Date getTimestamp(){
		return this.timestamp;
	}

	public void setKey(Key key) {
		this.key = key;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setTimestamp(Date timestamp) {
		this.timestamp = timestamp;
	}
	
	
}
